← 返回文章列表

Dify 1.17 升级实测(三):循环内人工审批与图片直传实测——两个高频场景的新解法

📖 摘要:1.17 把两个高频交付场景的能力补齐了:人工输入表单(HITL)终于能在 Iteration 循环内逐项暂停、逐项确认——审批流可以直接做了;图片直传多模态模型也打通了——上传、文件变量、vision 配置、视觉模型识别一条链路。但这两块都有新格式和新坑:迭代节点 DSL 大改、output_selector 收集格式、文件访问控制。本文是完整实测记录。

一、实验目的:两个被问过很多次的场景

做交付这些年,被问得最多的两个需求:

  1. 审批流:一批任务,每一项都要人工确认,能不能在循环里逐项暂停等确认?
  2. 图片理解:用户传一张图,让模型看——怎么传?哪个模型能看?

1.16 时代这两个需求都「能凑合」:审批流靠拆解成多次调用,图片得先转 URL 再想办法塞进提示词。1.17 把两个都做成了原生能力。本文实测这两条链路,验证它们到底能不能直接用于交付。

二、场景设计:两个贴近业务的实验

实验 A(审批流):输入「任务A,任务B」,工作流用 Iteration 遍历每项任务,每项暂停弹人工确认表单,确认后继续下一项,最终输出每项的人工确认结果数组。

实验 B(图片理解):用户上传一张测试图片(蓝色背景 + 左上角红色方块),LLM 节点配视觉模型 qwen-vl-plus,直传图片让它描述内容。

三、整体架构:两条链路

graph TD subgraph flow_a["审批流链路"] a1["输入任务数组"] --> a2["Iteration 逐项遍历"] a2 --> a3["人工确认表单(暂停等待)"] a3 -->|"提交确认"| a4["恢复执行(收集结果)"] a4 --> a2 end subgraph flow_b["图片理解链路"] b1["v1 上传图片"] --> b2["file 变量传入"] b2 --> b3["LLM 节点 vision 直传"] b3 --> b4["多模态模型识别"] end

四、迭代内人工输入(HITL in Iteration)

4.1 先说迭代格式:1.17 大改

实验第一件事就撞上了破坏性变更——1.17 的 iteration 节点格式和 1.16 完全不同:

# 1.17 的迭代节点(实测格式)

- id: iter_check

  data:

    type: iteration

    start_node_id: iter_start          # 迭代开始节点 ID

    iterator_selector: ["cd_items", "items"]    # 遍历的数组

    output_selector: ["cd_build", "result"]     # 收集每次迭代的输出(节点.字段)

    is_parallel: false

    parallel_nums: 10

    error_handle_mode: terminated

    flatten_output: true



# 迭代开始节点(类型也变了)

- id: iter_start

  data:

    type: iteration-start              # 1.16 是 custom-iteration-start

三个变化:itemsiterator_selectoroutputoutput_selector + start_node_id、迭代开始标记类型变了。迭代内节点不再需要 isInIteration/iteration_id/parentId 标记——范围由 start_node_id 界定,这是 1.17 的简化。

4.2 迭代内放人工输入:逐项暂停

工作流结构:code 节点生成数组 → Iteration 遍历 → 迭代内是「人工确认表单」→「组装结果」→ 迭代输出。

人工输入节点格式与 1.16 兼容(type=human-input / form_content / inputs / user_actions / timeout),迭代内引用当前项用 {{#iter_check.item#}}

- id: hi_confirm

  data:

    type: human-input

    title: 逐项确认

    form_content: "请确认任务「{{#iter_check.item#}}」:\n{{#confirm#}}"

    inputs:

      - type: paragraph

        label: 确认意见

        required: true

        output_variable_name: confirm

        default: {type: constant, value: "同意执行"}

    user_actions:

      - {id: approve, title: 同意, button_style: primary}

      - {id: reject, title: 拒绝, button_style: default}

    timeout: 1

    timeout_unit: hour

4.3 运行与恢复:每次迭代独立暂停

运行后工作流在第一个 human-input 处暂停(status=paused,elapsed 约 0.7 秒)。恢复链路三步:

1. GET /console/api/workflow/{run_id}/pause-details

   → paused_nodes[0].pause_type.form_id



2. 查数据库拿表单令牌(API 不给!):

   select access_token from human_input_form_recipients where form_id='...'



3. POST /console/api/form/human_input/{form_token}

   {"inputs": {"confirm": "同意执行任务A"}, "action": "approve"}

提交后工作流恢复,进入第二次迭代再次暂停——每次迭代一个独立表单。两项都确认后,流程跑完:

{"result": ["任务A|同意任务1", "任务B|同意任务2"]}

逐项确认结果正确收集。1.16 时代人工输入恢复时的竞态 bug(Client response stream closed)在 1.17 未复现——两次暂停恢复全稳定。

4.4 迭代输出收集的坑

output_selector 是本次实验最隐蔽的坑:必须写 [节点id, 字段] 格式["cd_build", "result"])。我们第一版写成了输出变量名 ["iter_result"]——运行成功、不报错,但迭代输出数组全是 null。静默失败,验收时容易漏。

五、多模态图片直传

5.1 三个配置点

# 1. 开始节点的文件变量

- id: start

  data:

    type: start

    variables:

      - label: 图片

        type: file

        variable: image

        required: true

        allowed_file_types: ["image"]   # 分类枚举:image/document/audio/video/custom



# 2. LLM 节点开 vision

- id: llm_v

  data:

    type: llm

    model: {provider: langgenius/tongyi/tongyi, name: qwen-vl-plus, mode: chat}

    prompt_template:

      - role: user

        text: "请描述这张图片的内容,用中文。"

    vision:

      enabled: true

      configs:

        variable_selector: ["start", "image"]

        detail: high

注意 allowed_file_types分类枚举(image/document/audio/video/custom),不是 MIME 类型——写 image/png 直接 400。

5.2 上传链路:必须走 service API

图片上传有个访问控制的坑:console 后台的上传接口(/console/api/files/upload)传的文件,service API 运行时引用会报 Invalid upload file——两套体系隔离。

正确姿势:用应用密钥走 service API 上传:

POST /v1/files/upload   (Authorization: Bearer 应用密钥,multipart 表单)

→ 拿到 upload_file_id



运行传参(file 变量是单个对象,不是数组):

{"image": {"type": "image", "transfer_method": "local_file", "upload_file_id": "..."}}

还有个隐蔽约束:文件绑定上传时的应用——同一个文件换了应用(重新导入的 app)引用就失效,每个被测应用要独立上传。

5.3 运行结果

测试图是程序生成的:蓝色背景 + 左上角红色方块。qwen-vl-plus 识别结果(3.9 秒):

这张图片非常简洁,主要由两种颜色构成:蓝色和红色。整体布局:大部分区域被纯蓝色填充;左上角有一个小的红色正方形……红色正方形在蓝色背景的衬托下显得格外突出。

颜色、位置、布局描述全部准确——图片直传链路完整可用。

六、运行验证汇总

验证项 方法 结果
迭代内逐项暂停 2 项数组 → 2 次独立暂停(form_id 不同)
恢复链路 表单提交 200 → 工作流恢复继续
迭代输出收集 output_selector 节点.字段格式 → 结果数组正确
图片直传 qwen-vl-plus 描述测试图(颜色/位置/布局)
文件访问控制 console 上传文件 service 引用报错 → v1 上传通过

七、实战坑:6 个坑

现象 修复
迭代 DSL 不兼容 1.16 格式导入 1.17 报错 按 4.1 新格式迁移
output_selector 写错 迭代输出数组静默 null 写 [节点id, 字段],验收断言非 null
form_token 拿不到 pause-details 只给 form_id DB 查 recipients 表
文件类型白名单 写 MIME(image/png)报 400 用分类枚举(image)
console 文件 service 不可见 Invalid upload file v1/files/upload 上传
文件跨应用失效 新 app 引用旧文件报错 每 app 独立上传

八、结论:两个能力都能直接交付

两个能力共同的提醒:1.17 的迭代格式是破坏性变更,存量迭代 DSL 要迁移;文件链路要按 service API 的规矩走。踩过这些坑,这两条链路就是顺手的能力。

📚 本系列其他篇:一、升级总览与 5 件事二、Agent V2 节点与技能包实测

实验文档与源码获取

本文基于 Dify 1.17.0 + Hermes Agent v0.21.0 实测,配置在不同版本间可能变化,使用前请确认版本。AI 参与创作声明:本文由 AI 辅助写作,内容基于作者真实实测记录。

这些 AI 应用能力,如何交付到真实业务场景?看看方案与服务 →
本系列 · Dify 实战
  1. Dify Agent 应用实战:Beta 版「真 Agent」的能力边界实测
  2. Dify workflow 与 Hermes Agent skill 的确定性对比
  3. Dify 意图分类节点总翻车?从 33% 失败率到兜底不崩——可靠性与韧性的三层加固
  4. Dify 标注回复实战:让智能客服记住人工答案的纠错闭环
  5. Dify 知识库元数据过滤实战:检索噪声 75% 降到 0 的确定性闸门
  6. RAG 建库,如何自动设置分段模式
  7. RAG知识库,如何进行持续更新运维
  8. RAG知识库的元数据过滤能力边界
  9. 数据库里的结构化数据,怎么建立 RAG 知识库?两条路线与选型判断
  10. 流程卡在「等人审批」?把审批链接送到企业微信和邮箱
  11. Dify 1.17 升级实测(一):从工作流平台到 Agent 平台,升级前必须知道的 5 件事
  12. Dify 应用上架门户:分享页每次回答都挂着内部流程节点?一个字段关掉
  13. RAG 知识库交付实战(上):4277 页手册喂给 AI——从凌晨故障到三模块方案
  14. RAG 知识库建库前,数据到底该怎么清洗?一条可复用的清洗管线实测
  15. 我们的门户机器人,为什么用 Dify 答、不把 skill 搬上云端 Hermes?
  16. 知识库从需求到交付:清洗、入库、维护全流程,照着走、每一步都能验证
  17. Dify 1.17 升级实测(二):Agent V2 节点与技能包实测——配置在数据库,不在 DSL
  18. RAG 知识库交付实战(中):三大深坑与修复实录——流程图截断/限流风暴/并联污染
  19. DeepSeek 思考模式什么情况下可以关?一次空输出事故的排查实录
  20. Dify 1.17 升级实测(三):循环内人工审批与图片直传实测——两个高频场景的新解法
  21. Dify 定时触发(trigger-schedule)实测:工作流到点自动跑,和三个必须知道的坑
  22. Dify 知识库三种分段模式实测:通用、父子、Q&A 到底怎么选?
  23. Dify 知识库接入 Notion/网页:先搞清三件事,再谈清洗
  24. RAG 知识库交付实战(下):18 条用例与成本测算
  25. 知识库数据清洗后,怎么知道洗得干不干净?一套三层质量门禁实测
  26. Dify 实战:供应商报价单格式五花八门,AI 怎么知道哪列是单价?

联系我

邮箱contact@fishsun.cn

点击邮箱直接写信 · 扫码加微信沟通

微信

微信二维码

扫码加微信 · 备注「门户」更快通过